<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head th:include="include/header::html('股票趋势模拟回测')"></head>

<body>
<script>
    var chart4Profit = null;

    $(function () {
        var data4Vue = {
            stockCode: '',  // 股票代码

            indexes: [],  // 股票代码集合
            currentIndex: '',

            // indexDatas 就表示代码数据数组。
            // dates 代表日期数组。
            // closePoints 代表收盘点数组。
            indexDatas: [],
            dates: [],
            closePoints: [],

            // 用于判断是否要更新日期
            // 为什么要这个呢？ 现在其实有两种获取数据需求，一种是既获取指数数据，也要获取日期数据，另一个种是仅仅获取指数数据.
            // 比如切换指数代码，就两则都要。
            // 而调整日期，则不需要获取日期，而是仅仅获取指数数据。
            flushDate: true,

            stockStartDate: null,
            stockEndDate: null,
            startDate: null,
            endDate: null,

            // profits 就是服务器返回的对象，但是它是 Profit 类型的数组，并不是在作图的时候需要的
            // 作图的时候，仅仅需要其中的 Value ，所以再准备一个 profitValues 数组用于存放作图用的 Value。
            profits: [],
            profitValues: [],

            // 交易记录数组
            trades: [],

            // 指定日期区间的年数
            years: 0,
            indexIncomeTotal: 0,
            indexIncomeAnnual: 0,
            trendIncomeTotal: 0,
            trendIncomeAnnual: 0,

            // 交易统计
            winCount: 0,
            lossCount: 0,
            avgWinRate: 0,
            avgLossRate: 0,

            annualProfits: [],  // 每年收益数组
            annuals: [],  // 年数组，图表里的横轴
            stockIncomes: [],  // 股票投资收益数组，图表里的纵轴
            trendIncomes: [],  // 趋势投资收益数组，图表里的纵轴

            ma: 20,  // 均线
            buyThreshold: 1.01,  // 买入阈值
            sellThreshold: 0.99,  // 卖出阈值

            serviceCharge: 0.0,  // 手续费

            recommendedLevel: 0,  // 推荐等级
        };

        console.log("data4Vue.stockCode:" + data4Vue.stockCode)

        //ViewModel
        var vue = new Vue({
            el: '#workingArea',
            data: data4Vue,
            mounted: function () { //mounted　表示这个 Vue 对象加载成功了
                this.init();
                $("[data-toggle='tooltip']").tooltip();
            },
            methods: {
                init: function () {
                    var url = "http://127.0.0.1:8000/stockCode/getStockCode";
                    // window.print()
                    axios.get(url).then(function (response) {
                        console.log(response.data);
                        vue.indexes = response.data;
                        vue.$nextTick(function () {
                            vue.simulate();
                        });
                    });
                },

                pullStockData: function () {
                    var url = "http://localhost:8000/stockData/pullStockData/" + vue.stockCode + "/";
                    axios.get(url).then(function (response) {
                        console.log("response:", response);
                        alert(response.data.msg);
                        location.reload();
                    });
                },

                simulate: function () {
                    console.log("vue.currentIndex:" + vue.currentIndex);
                    // var url = "http://localhost:8000/stockData/obtainStockData?stockCode=" + vue.currentIndex+"&strStartDate="+vue.startDate+"&strEndDate="+vue.endDate;
                    var url = "http://localhost:8000/stockData/obtainStockData/" + vue.currentIndex + "/" + vue.ma + "/" + vue.buyThreshold + "/" + vue.sellThreshold + "/" + vue.serviceCharge + "/" + vue.startDate + "/" + vue.endDate;
                    // console.log("url:" + url);
                    axios.get(url).then(function (response) {
                        //清空原数据
                        vue.indexDatas = [];
                        vue.dates = [];
                        vue.closePoints = [];
                        vue.profits = [];
                        vue.profitValues = [];
                        vue.trades = [];

                        vue.annualProfits = [];
                        vue.annuals = [];
                        vue.stockIncomes = [];
                        vue.trendIncomes = [];
                        // console.log("response.data.stockData:" + response.data.stockData);
                        //获取返回数据
                        vue.indexDatas = response.data.stockData;
                        vue.dates = new Array();
                        vue.closePoints = new Array();

                        //日期
                        vue.stockStartDate = response.data.stockStartDate;
                        vue.stockEndDate = response.data.stockEndDate;

                        //收益
                        vue.profits = response.data.profits;
                        console.log("vue.profits.length:" + vue.profits.length);
                        // console.log("vue.profits:" + vue.profits);

                        // 交易细明
                        vue.trades = response.data.trades;

                        // 收益一览
                        vue.years = response.data.years;
                        vue.indexIncomeTotal = response.data.indexIncomeTotal;
                        vue.indexIncomeAnnual = response.data.indexIncomeAnnual;
                        vue.trendIncomeTotal = response.data.trendIncomeTotal;
                        vue.trendIncomeAnnual = response.data.trendIncomeAnnual;


                        // 交易统计
                        vue.winCount = response.data.winCount;
                        vue.lossCount = response.data.lossCount;
                        vue.avgWinRate = response.data.avgWinRate;
                        vue.avgLossRate = response.data.avgLossRate;

                        // 每年收益
                        vue.annualProfits = response.data.annualProfits;

                        // 推荐等级
                        vue.recommendedLevel = response.data.recommendedLevel;


                        // 股票数据
                        for (i in vue.indexDatas) {
                            // for (i in vue.indexDatas) {
                            var indexData = vue.indexDatas[i];
                            // 股票数据日期
                            vue.dates.push(indexData.date);
                            // 股票数据收盘价
                            vue.closePoints.push(indexData.closingPrice);

                            // profits 转换为 profitValues
                            var profit = vue.profits[i];
                            vue.profitValues.push(profit.value);
                        }

                        // 计算出图表需要的横纵和纵轴数据
                        for (i in vue.annualProfits) {
                            vue.annuals.push(vue.annualProfits[i].year);
                            vue.stockIncomes.push(vue.annualProfits[i].stockIncome * 100);
                            vue.trendIncomes.push(vue.annualProfits[i].trendIncome * 100);
                        }

                        //收益图标
                        chart4Profit.config.data.labels = vue.dates;
                        chart4Profit.config.data.datasets[0].label = vue.currentIndex;
                        chart4Profit.config.data.datasets[0].data = vue.closePoints;
                        // 收益图里设置收益曲线
                        chart4Profit.config.data.datasets[1].data = vue.profitValues;
                        chart4Profit.update();

                        // 每年收益图表更新
                        chart4AnnualIncome.config.data.labels = vue.annuals;
                        chart4AnnualIncome.config.data.datasets[0].label = vue.currentIndex;
                        chart4AnnualIncome.config.data.datasets[0].data = vue.stockIncomes;
                        chart4AnnualIncome.config.data.datasets[1].data = vue.trendIncomes;
                        chart4AnnualIncome.update();

                        // 表示如果flushDate 是true，就会刷新日期，默认是 true, 即一开始就会刷新日期
                        if (vue.flushDate)
                            vue.updateDate();
                    });
                },
                // 需要刷新日期的时候调用
                changeParam: function () {
                    vue.flushDate = false;
                    vue.simulate();
                },
                // 不需要刷新日期的时候调用
                changeParamWithFlushDate: function () {
                    vue.flushDate = true;
                    vue.startDate = null;
                    vue.endDate = null;
                    vue.simulate();
                },
                updateDate: function () {
                    vue.startDate = vue.stockStartDate;
                    vue.endDate = vue.stockEndDate;

                    console.log("vue.stockStartDate：" + vue.stockStartDate);

                    //需要先destroy，否则后续新的日期范围如果超出了前面的日期范围，会出冲突
                    $('#date4Start').datepicker("destroy");
                    $('#date4Start').datepicker({
                        "format": 'yyyy-mm-dd',
                        "language": "zh-CN",
                        autoclose: true,
                        startDate: vue.stockStartDate,
                        endDate: vue.stockEndDate,
                    }).on("changeDate", function (e) {
                        var month = (e.date.getMonth() + 1);
                        if (month < 10)
                            month = '0' + month;
                        var day = (e.date.getDate());
                        if (day < 10)
                            day = '0' + day;
                        vue.startDate = e.date.getFullYear() + "-" + month + "-" + day;

                        if (!vue.checkDateRange()) {
                            $('#date4Start').datepicker('update', vue.stockStartDate);
                            return;
                        }

                        vue.changeParam();
                    });

                    $('#date4End').datepicker("destroy");
                    $('#date4End').datepicker({
                        "format": 'yyyy-mm-dd',
                        "language": "zh-CN",
                        autoclose: true,
                        startDate: vue.stockStartDate,
                        endDate: vue.stockEndDate,
                    }).on("changeDate", function (e) {
                        var month = (e.date.getMonth() + 1);
                        if (month < 10)
                            month = '0' + month;
                        var day = (e.date.getDate());
                        if (day < 10)
                            day = '0' + day;
                        vue.endDate = e.date.getFullYear() + "-" + month + "-" + day;
                        if (!vue.checkDateRange()) {
                            $('#date4End').datepicker('update', vue.stockEndDate);
                            return;
                        }

                        vue.changeParam();

                    });

                    console.log("vue.stockStartDate:" + vue.stockStartDate);
                    console.log("vue.stockEndDate:" + vue.stockEndDate);

                    $('#date4Start').datepicker('update', vue.stockStartDate);
                    $('#date4End').datepicker('update', vue.stockEndDate);
                },
                checkDateRange: function () {
                    if (null == vue.startDate || null == vue.endDate)
                        return true;

                    var strStartDate = vue.startDate.replace(/-/g, '/')
                    var startTime = new Date(strStartDate).getTime();
                    var strEndDate = vue.endDate.replace(/-/g, '/')
                    var endTime = new Date(strEndDate).getTime();
                    if (startTime > endTime) {
                        alert("开始日期不能大于日期！");
                        return false;
                    }
                    return true;

                }
            }
        });

        var ctx4Profit = $(".canvas4Profit")[0].getContext('2d');
        chart4Profit = new Chart(ctx4Profit, {
            type: 'line',
            data: {
                labels: '',
                datasets: [
                    {
                        label: '',
                        data: [],
                        borderColor: '#FF4040',
                        backgroundColor: '#FF4040',
                        borderWidth: 1.2,
                        pointRadius: 0,
                        fill: false,
                        lineTension: 0,
                    }, {
                        label: '趋势投资',
                        data: [],
                        borderColor: '#5D98C8',
                        backgroundColor: '#5D98C8',
                        borderWidth: 1.2,
                        pointRadius: 0,
                        fill: false,
                        lineTension: 0,
                    }
                ]
            },
            options: {
                title: {
                    display: true,
                    text: '股票趋势投资收益对比图'
                },
                responsive: true,
                responsiveAnimationDuration: 3000,
                scales: {
                    yAxes: [{
                        ticks: {
                            beginAtZero: false,
                        }
                    }]
                },
                tooltips: {
                    intersect: false,
                    mode: 'index',
//                      axis: 'y',
                    callbacks: {
                        label: function (tooltipItem, myData) {
                            var label = myData.datasets[tooltipItem.datasetIndex].label || '';
                            if (label) {
                                label += ': ';
                            }
                            label += parseFloat(tooltipItem.value).toFixed(2);
                            return label;
                        }
                    }
                }
            }
        });
        var ctx4AnnualIncome = $(".canvas4AnnualIncome")[0].getContext('2d');
        chart4AnnualIncome = new Chart(ctx4AnnualIncome, {
            type: 'bar',
            data: {
                labels: '',
                datasets: [
                    {
                        label: '',
                        data: [],
                        borderColor: '#FF4040',
                        backgroundColor: '#FF4040',
                        borderWidth: 1,
                        pointRadius: 0,
                        fill: false,
                        lineTension: 0,
                    },
                    {
                        label: '趋势投资',
                        data: [],
                        borderColor: '#5D98C8',
                        backgroundColor: '#5D98C8',
                        borderWidth: 1,
                        pointRadius: 0,
                        fill: false,
                        lineTension: 0,
                    }
                ]
            },
            options: {
                title: {
                    display: true,
                    text: '股票/趋势收益分布对比图'
                },
                responsive: true,
                responsiveAnimationDuration: 3000,
                scales: {
                    yAxes: [{
                        ticks: {
                            beginAtZero: true,
//                              suggestedMin: -10,
//                              suggestedMax: 200,
                        }
                    }]
                },
                tooltips: {
                    intersect: false,
                    mode: 'stock',

                    callbacks: {
                        label: function (tooltipItem, myData) {
                            var label = myData.datasets[tooltipItem.datasetIndex].label || '';
                            if (label) {
                                label += ': ';
                            }
                            label += parseFloat(tooltipItem.value).toFixed(2);
                            label += "%";
                            return label;
                        }
                    }
                }
            }
        });

    });


</script>

<style>
    table.inputTable {
        width: 100%;
    }

    table.inputTable td {
        padding: 20px 20px;
    }

    table {
        margin: 20px;
    }

    div#workingArea {
        margin: 50px;
    }

    button {
        background-color: #4CAF50; /* Green */
        border: none;
        color: white;
        padding: 8px 30px;
        /*字体位置*/
        text-align: center;
        margin-top: -5px;
        text-decoration: none;
        display: inline-block;
        /*字体大小*/
        font-size: 14px;
        /*圆角*/
        border-radius: 5px;
    }
</style>

<div id="workingArea">
    <span class="label label-info">回测参数</span>
    <table class="inputTable ">
        <tr>
            <td width="25%">
                <span data-toggle="tooltip" data-placement="top" title="选择某一个股票进行模拟回测">
                    请选择股票代码:<span class="glyphicon glyphicon-question-sign"> </span>
                </span>
            </td>
            <td width="25%">
                <label>
                    <!--@change监听变化-->
                    <select @change="changeParamWithFlushDate" v-model="currentIndex" class="indexSelect form-control">
                        <option v-for="(bean, key) in indexes" :value="key">{{bean.name}} - ({{bean.code}})
                        </option>
                    </select>
                </label>
            </td>
            <td width="25%"></td>
            <td width="25%"></td>
        </tr>
        <tr>
            <td>
            <span data-toggle="tooltip" data-placement="top"
                  title="沪市股票代码前加0，深市股票代码前加1，如上证指数应为0000001">
                请输入股票代码 :<span class="glyphicon glyphicon-question-sign	"> </span>
            </span>
            </td>
            <td>
                <label>
                    <input class="form-control" v-model="stockCode"/>
                </label>
            </td>
            <td>
                <button @click="pullStockData">获取股票数据</button>
            </td>
        </tr>
        <tr>
            <td>
            <span data-toggle="tooltip" data-placement="top"
                  title="0代表最低，5代表最高">
                推荐等级 :<span class="glyphicon glyphicon-question-sign	"> </span>
            </span>
            </td>
            <td>
                <label>
                    <input class="form-control" v-model="recommendedLevel"/>
                </label>
            </td>
        </tr>
        <tr>
            <td>
                <span data-toggle="tooltip" data-placement="top"
                      title="MA 即 moving average, 移动均线的意思。 比如MA20就表示20日均线，取最近20天的值的平均数">
                    MA(均线) :<span class="glyphicon glyphicon-question-sign	"> </span>
                </span>
            </td>
            <td>
                <select class="form-control" @change="changeParam" v-model="ma">
                    <option value="5">5日</option>
                    <option value="10">10日</option>
                    <option value="20">20日</option>
                    <option value="30">30日</option>
                    <option value="60">60日</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>
                <span data-toggle="tooltip" data-placement="top"
                      title="当前值大于均线，说明上升趋势来了，就可以购买，或者再稍等等，比均线多 5% 再下手，那么购买阈值就是 1.05 ">
                    购买阈值:<span class="glyphicon glyphicon-question-sign	"> </span>
                </span>
            </td>
            <td>
                <select class="form-control" @change="changeParam" v-model="buyThreshold">
                    <option v-for="i in 9" :value="i/100+1">{{i/100+1|formatNumberFilter(2)}}</option>
                </select>
            </td>
            <td>
                <span data-toggle="tooltip" data-placement="top"
                      title="当前值低于均线，说明下跌趋势来了，就可以出售，或者再稍等等，比最近的高点低 5%，那么购买阈值就是 0.95">
                    出售阈值:<span class="glyphicon glyphicon-question-sign	"> </span>
                </span>
            </td>
            <td>
                <select class="form-control" @change="changeParam" v-model="sellThreshold">
                    <option v-for="i in 10" :value="1-i/100">{{1-i/100|formatNumberFilter(2)}}</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>
                <span data-toggle="tooltip" data-placement="top" title="每一笔交易都会有手续费，一般说来手续费都不高，千分之 1.5 的左右，默认是没有计算手续费的">
                    手续费:<span class="glyphicon glyphicon-question-sign"> </span>
                </span>
            </td>
            <td>
                <select class="form-control" @change="changeParam" v-model="serviceCharge">
                    <option value="0">无</option>
                    <option value="0.001">0.1%</option>
                    <option value="0.0015">0.15%</option>
                    <option value="0.002">0.2%</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>
                <span data-toggle="tooltip" data-placement="top" title="指定模拟回测的开始日期，默认是当前指数最开始的日期">
                    开始日期:<span class="glyphicon glyphicon-question-sign  "> </span>
                </span>
            </td>
            <td>
                <div class="form-group">
                    <div class="input-group date" id="date4Start">
                        <input type="text" readOnly="readOnly" class="form-control">
                        <span class="input-group-addon">
                            <i class="glyphicon glyphicon-th"></i>
                        </span>
                    </div>
                </div>
            </td>
            <td>
                <span data-toggle="tooltip" data-placement="top" title="指定模拟回测的结束日期，默认是当前指数最后的日期">
                    结束日期:<span class="glyphicon glyphicon-question-sign  "> </span>
                </span>
            </td>
            <td>
                <div class="form-group">
                    <div class="input-group date" id="date4End">
                        <input type="text" readOnly="readOnly" class="form-control">
                        <span class="input-group-addon">
                            <i class="glyphicon glyphicon-th"></i>
                        </span>
                    </div>
                </div>
            </td>

        </tr>
    </table>
    <div class="label label-warning">收益对比图</div>

    <div class="div4chart" style="margin:0 auto; width:80%">
        <canvas class='canvas4Profit'></canvas>
    </div>

    <div class="label label-warning">收益一览</div>

    <table class="table table-striped table-bordered table-condensed">
        <thead>
        <th>投资类型</th>
        <th>投资时长 (年)</th>
        <th>1000元投资收益</th>
        <th>总收益率</th>
        <th>年化收益率</th>
        </thead>
        <tbody>
        <tr>
            <td>股票投资</td>
            <td>{{years|formatNumberFilter(2)}}</td>
            <td>{{(indexIncomeTotal+1)*1000|formatMoneyFilter}}</td>
            <td>{{indexIncomeTotal*100|formatNumberFilter(2)}}%</td>
            <td>{{indexIncomeAnnual*100|formatNumberFilter(2)}}%</td>
        </tr>
        <tr>
            <td>趋势投资</td>
            <td>{{years|formatNumberFilter(2)}}</td>
            <td>{{(trendIncomeTotal+1)*1000|formatMoneyFilter}}</td>
            <td>{{trendIncomeTotal*100|formatNumberFilter(2)}}%</td>
            <td>{{trendIncomeAnnual*100|formatNumberFilter(2)}}%</td>
        </tr>
        <tr>
            <td>相对收益</td>
            <td>n/a</td>
            <td>{{(trendIncomeTotal-indexIncomeTotal)*1000|formatMoneyFilter}}</td>
            <td>{{(trendIncomeTotal-indexIncomeTotal)*100|formatNumberFilter(2)}}%</td>
            <td>{{(trendIncomeAnnual-indexIncomeAnnual)*100|formatNumberFilter(2)}}%</td>
        </tr>
        </tbody>
    </table>

    <div class="label label-warning">交易统计</div>
    <table class="table table-bordered table-condensed">
        <thead>
        <th align="center" colspan="2">趋势投资盈亏统计</th>
        </thead>
        <tbody>
        <tr>
            <td width="50%">总共交易次数</td>
            <td>{{winCount+lossCount}}</td>
        </tr>
        <tr>
            <td>盈利交易次数</td>
            <td>{{winCount}}</td>
        </tr>
        <tr>
            <td>平均盈利比率</td>
            <td>{{avgWinRate*100|formatNumberFilter(2)}}%</td>
        </tr>
        <tr>
            <td>亏损交易次数</td>
            <td>{{lossCount}}</td>
        </tr>
        <tr>
            <td>平均亏损比率</td>
            <td>{{avgLossRate*100|formatNumberFilter(2)}}%</td>
        </tr>
        <tr>
            <td>胜率</td>
            <td>{{(winCount/(winCount+lossCount))*100|formatNumberFilter(2)}}%</td>
        </tr>

        </tbody>
    </table>

    <div class="label label-warning">收益分布对比表</div>
    <table class="table table-striped table-bordered table-condensed">
        <thead>
        <th>年份</th>
        <th>股票投资收益</th>
        <th>趋势投资收益</th>
        </thead>
        <tbody>
        <tr v-for="bean in annualProfits">
            <td>
                {{bean.year}}
            </td>
            <td>
                {{bean.stockIncome*100|formatNumberFilter(2)}}%
            </td>
            <td>
                {{bean.trendIncome*100|formatNumberFilter(2)}}%
            </td>
        </tr>
        </tbody>
    </table>

    <div class="label label-warning">收益分布对比图</div>

    <div class="div4chart" style="margin:0px auto; width:80%">
        <canvas class='canvas4AnnualIncome'></canvas>
    </div>

    <div class="label label-warning">交易细明</div>

    <table class="table table-striped table-bordered table-condensed table-hover">
        <thead>

        <th>盈/亏</th>
        <th>购买日期</th>
        <th>购买盘点</th>
        <th>出售日期</th>
        <th>出售盘点</th>
        <th>盈亏比率</th>
        <th>1000元投资收益</th>
        </thead>
        <tbody>
        <tr v-for="bean in trades">
            <td>
                <span v-if="bean.sellClosePoint>bean.buyClosePoint" class="label label-danger">盈利</span>
                <span v-if="bean.sellClosePoint<=bean.buyClosePoint" class="label label-success">亏损</span>

            </td>
            <td>{{bean.buyDate}}</td>
            <td>{{bean.buyClosePoint}}</td>
            <td>{{bean.sellDate}}</td>
            <td>

                <span v-if="bean.sellClosePoint==0">n/a</span>
                <span v-if="bean.sellClosePoint!=0">{{bean.sellClosePoint}}</span>

            </td>
            <td>
                <span v-if="bean.sellClosePoint==0">n/a</span>

                <span class="label"
                      v-bind:class="{ 'label-danger' : bean.sellClosePoint>bean.buyClosePoint, 'label-success' : bean.sellClosePoint<=bean.buyClosePoint }"
                      v-if="bean.sellClosePoint!=0">{{(bean.sellClosePoint-bean.buyClosePoint)*100/bean.buyClosePoint | formatNumberFilter(2)}}%
                </span>

            </td>
            <td>
                <span v-if="bean.sellClosePoint==0">n/a</span>
                <span v-if="bean.sellClosePoint!=0">{{bean.rate*1000 | formatMoneyFilter }}</span>

            </td>
        </tr>

        </tbody>

    </table>
</div>

<div th:replace="include/footer::html"></div>

</body>
</html>
